package cn.test.dao.base;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

@SuppressWarnings("unchecked")
public class BaseDao<T,ID extends Serializable> extends NamedParameterJdbcDaoSupport {
	protected Class<T> entityClass;
	protected Class<ID> idClass;
	
	protected Class<T> getEntityClass() {
		if (entityClass == null) {
			entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		}
		return entityClass;
	}
	protected Class<ID> getIdClass() {
		if (idClass == null) {
			idClass = (Class<ID>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		}
		return idClass;
	}
	@Autowired
	protected void setDatasource(DataSource dataSource) {
		super.setDataSource(dataSource);
	}

	public ID insert(final String sql,final Object...params) {
		KeyHolder keyHolder = new GeneratedKeyHolder();
		this.getJdbcTemplate().update(new PreparedStatementCreator() {
			@Override
			public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
				PreparedStatement ps = con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
				for (int i=0;i<params.length;i++) {
					ps.setObject(i+1,params[i]);
				}
				return ps;
			}
		},keyHolder);
		return TransformKeyTool.getId(keyHolder, getIdClass());
	}
	
	public List<T> find(String sql,Object...params){
		return this.getJdbcTemplate().query(sql, new BeanPropertyRowMapper<T>(getEntityClass()),params);
	}
	
	public int update(String sql,Object...params){
		return this.getJdbcTemplate().update(sql, params);
	}
	
	public T get(String sql,ID key){
		return this.getJdbcTemplate().queryForObject(sql, new BeanPropertyRowMapper<T>(getEntityClass()),key);
	}
	/**
	 * 查找单个对象
	 * @param sql
	 * @param params
	 * @return
	 */
	public T query(String sql,Object ...params){
		try {
			return this.getJdbcTemplate().queryForObject(sql, new BeanPropertyRowMapper<T>(getEntityClass()),params);
		} catch (EmptyResultDataAccessException e) {
			return null;
		}
	}
	/**
	 * 查找单个对象，不使用mapper代理
	 * @param sql
	 * @param mapper
	 * @param params
	 * @return
	 */
	public T query(String sql,RowMapper<T> mapper,Object ...params){
		try {
			return this.getJdbcTemplate().queryForObject(sql, mapper,params);
		} catch (EmptyResultDataAccessException e) {
			return null;
		}
	}
	
	/**
	 * 查找单个对象，不使用mapper代理
	 * @param sql
	 * @param mapper
	 * @param params
	 * @return
	 */
	public <V> V queryForObject(String sql,RowMapper<V> mapper,Object ...params){
		try {
			return this.getJdbcTemplate().queryForObject(sql, mapper,params);
		} catch (EmptyResultDataAccessException e) {
			return null;
		}
	}
	
	public <V> V queryForObject(String sql,Class<V> requiredType,Object ...params){
		try {
			return this.getJdbcTemplate().queryForObject(sql, requiredType, params);
		} catch (EmptyResultDataAccessException e) {
			return null;
		}
	}
}
